/*
 * AWN plugin for GAIM
 * Copyright (C) 2007 Michael (mycroes) Croes <mycroes@gmail.com>
 * Copyright from other people that wrote code with another purpose:
 * Copyright (C) 2002-3 Robert McQueen <robot101@debian.org>
 * Copyright (C) 2003 Herman Bloggs <hermanator12002@yahoo.com>
 *
 * Inspired by a similar plugin by:
 * Robert McQueen <robot101@debian.org>
 * Herman Bloggs <hermanator12002@yahoo.com>
 * Which was in turn inspired by a similar plugin by:
 *  John (J5) Palmieri <johnp@martianrock.com>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 * 02111-1307, USA.
 */

#define GAIM_PLUGINS

#include <stdlib.h>
#include <glib.h>
#include <dbus/dbus-glib.h>
#include <dbus/dbus-glib-bindings.h>

#include "gtkgaim.h"
#include "gtkconv.h"

#include "notify.h"
#include "plugin.h"
#include "version.h"

#include "gaim_awn.h"

static AwnStatus status = AWN_STATUS_OFFLINE;
static guint awn_blinking_timer = 0;

static GaimPluginInfo info = {
	GAIM_PLUGIN_MAGIC,
	GAIM_MAJOR_VERSION,
	GAIM_MINOR_VERSION,
	GAIM_PLUGIN_STANDARD,
	NULL,
	0,
	NULL,
	GAIM_PRIORITY_DEFAULT,
	
	"AWN plugin",
	"AWN plugin",
	VERSION,
	
	"Avant Window Navigator plugin",
	"A plugin for Gaim to show useful information in AWN",
	NULL,
	"http://code.google.com/p/awn-plugins",

	plugin_load,
	plugin_unload,
	NULL,
	
	NULL,
	NULL,
	NULL,
	NULL
};

static void setAwnIcon(char *filename) {
	DBusGConnection *connection;
	DBusGProxy *proxy;
	GError *error;	

	g_type_init();
	
	error = NULL;
	connection = dbus_g_bus_get(DBUS_BUS_SESSION, &error);
	
	if (connection != NULL)
	{
		proxy = dbus_g_proxy_new_for_name(
				connection,
				"com.google.code.Awn",
				"/com/google/code/Awn",
				"com.google.code.Awn");
		error = NULL;
		dbus_g_proxy_call(proxy, "SetTaskIconByName", &error, G_TYPE_STRING,
				"gaim", G_TYPE_STRING, filename, G_TYPE_INVALID);
	}
}

static void unsetAwnIcon() {
	DBusGConnection *connection;
	DBusGProxy *proxy;
	GError *error;	
	
	g_type_init();
	
	error = NULL;
	connection = dbus_g_bus_get(DBUS_BUS_SESSION, &error);
	
	if (connection != NULL)
	{
		proxy = dbus_g_proxy_new_for_name(
				connection,
				"com.google.code.Awn",
				"/com/google/code/Awn",
				"com.google.code.Awn");
		error = NULL;
		dbus_g_proxy_call(proxy, "UnsetTaskIconByName", &error,
				G_TYPE_STRING, "gaim", G_TYPE_INVALID);
	}
}

static void setAwnInfo(char *info) {
	DBusGConnection *connection;
	DBusGProxy *proxy;
	GError *error;	
	
	g_type_init();
	
	error = NULL;
	connection = dbus_g_bus_get(DBUS_BUS_SESSION, &error);
	
	if (connection != NULL)
	{
		proxy = dbus_g_proxy_new_for_name(
				connection,
				"com.google.code.Awn",
				"/com/google/code/Awn",
				"com.google.code.Awn");
		error = NULL;
		dbus_g_proxy_call(proxy, "SetInfoByName", &error, G_TYPE_STRING,
				"gaim", G_TYPE_STRING, info, G_TYPE_INVALID);
	}
}

static void unsetAwnInfo() {
	DBusGConnection *connection;
	DBusGProxy *proxy;
	GError *error;	
	
	g_type_init();
	
	error = NULL;
	connection = dbus_g_bus_get(DBUS_BUS_SESSION, &error);
	
	if (connection != NULL)
	{
		proxy = dbus_g_proxy_new_for_name(
				connection,
				"com.google.code.Awn",
				"/com/google/code/Awn",
				"com.google.code.Awn");
		error = NULL;
		dbus_g_proxy_call(proxy, "UnsetInfoByName", &error, G_TYPE_STRING,
				"gaim", G_TYPE_INVALID);
	}
}

/****************************
 * helper functions
 ****************************/

static void update_icon(AwnStatus newStatus) {
	switch (newStatus) {
		case AWN_STATUS_OFFLINE:
			setAwnIcon(PATH_IMG_OFFLINE);
			break;
		case AWN_STATUS_ONLINE:
			setAwnIcon(PATH_IMG_ONLINE);
			break;
		case AWN_STATUS_ONLINE_PENDING:
			setAwnIcon(PATH_IMG_ONLINE_PENDING);
			break;
		case AWN_STATUS_AWAY:
			setAwnIcon(PATH_IMG_AWAY);
			break;
		case AWN_STATUS_AWAY_PENDING:
			setAwnIcon(PATH_IMG_AWAY_PENDING);
			break;
		default:
			setAwnIcon(PATH_IMG_CONNECTING);
	}
}

static GList * get_pending_list(guint max)
{
	GList *l_im = NULL;
	GList *l_chat = NULL;
	
	l_im = gaim_gtk_conversations_find_unseen_list(GAIM_CONV_TYPE_IM,
			GAIM_UNSEEN_TEXT, FALSE, max);
	
	l_chat = gaim_gtk_conversations_find_unseen_list(GAIM_CONV_TYPE_CHAT,
			GAIM_UNSEEN_NICK, FALSE, max);
	
	if (l_im != NULL && l_chat != NULL)
		return g_list_concat(l_im, l_chat);
	else if (l_im != NULL)
		return l_im;
	else
		return l_chat;
}

/****************************
 * the real work
 ****************************/

static gboolean
awn_blink_icon()
{
	static gboolean blinked = FALSE;
	gboolean ret = FALSE; /* by default, don't keep blinking */

	blinked = !blinked;

	switch (status) {
		case AWN_STATUS_ONLINE_PENDING:
		case AWN_STATUS_AWAY_PENDING:
			if (blinked) {
				update_icon(status - 1);
			} else {
				update_icon(status);
			}
			ret = TRUE; /* keep blinking */
			break;
		default:
			awn_blinking_timer = 0;
			blinked = FALSE;
			break;
	}

	return ret;
}

static gboolean awn_update_status()
{
	GList *convs, *l;
	int count;
	AwnStatus newstatus = AWN_STATUS_OFFLINE;
	gboolean pending = FALSE;
	
	/* unseen messages */ /* no need to limit for awn :) */
	convs = get_pending_list(0); /* DOCKLET_TOOLTIP_LINE_LIMIT */
	
	if (convs != NULL) {
		pending = TRUE;
		/* set tooltip if messages are pending */
		if (1) { /* if (showInfo/Tooltip) */
			for (l = convs, count = 0; l != NULL; l = l->next, count++) {
				if (GAIM_IS_GTK_CONVERSATION(l->data)) {
					/* conv to count */
					GaimGtkConversation *gtkconv = GAIM_GTK_CONVERSATION((GaimConversation *)l->data);
					
					printf("%u\n", gtkconv->unseen_count);
				}
			}
		}
		
		g_list_free(convs);
	} else {
		unsetAwnInfo();
	}
	
	for (l = gaim_accounts_get_all(); l != NULL; l = l->next) {
		AwnStatus tmpstatus = AWN_STATUS_OFFLINE;
		
		GaimAccount *account = (GaimAccount *)l->data;
		GaimStatus *account_status;
		
		if (!gaim_account_get_enabled(account, GAIM_GTK_UI))
			continue;
		
		if (gaim_account_is_disconnected(account))
			continue;
		
		account_status = gaim_account_get_active_status(account);
		
		if (gaim_account_is_connecting(account)) {
			tmpstatus = AWN_STATUS_CONNECTING;
		} else if (gaim_status_is_online(account_status)) {
			if (!gaim_status_is_available(account_status)) {
				if (pending)
					tmpstatus = AWN_STATUS_AWAY_PENDING;
				else
					tmpstatus = AWN_STATUS_AWAY;
			}
			else {
				if (pending)
					tmpstatus = AWN_STATUS_ONLINE_PENDING;
				else
					tmpstatus = AWN_STATUS_ONLINE;
			}
		}
		
		if (tmpstatus > newstatus)
			newstatus = tmpstatus;
		
	}
	
	if (status != newstatus) {
		status = newstatus;
		
		update_icon(status);
		
		if ((status == AWN_STATUS_ONLINE_PENDING ||
				status == AWN_STATUS_AWAY_PENDING) &&
				awn_blinking_timer == 0) { /* if (blink) */
			awn_blinking_timer = g_timeout_add(500, awn_blink_icon, NULL);
		}
	}
	
	return FALSE;
}
			
		

/****************************
 * callbacks
 ****************************/

static void awn_update_status_cb(void *data)
{
	awn_update_status();
}

static void awn_conv_updated_cb(GaimConversation *conv, GaimConvUpdateType type)
{
	if (type == GAIM_CONV_UPDATE_UNSEEN)
		awn_update_status();
}

static void awn_signon_cb(GaimConnection *gc)
{
	awn_update_status();
}

static void awn_signoff_cb(GaimConnection *gc)
{
	awn_update_status();
}

static void buddy_signon_cb(GaimBuddy *buddy) {
	
}

static void buddy_signoff_cb(GaimBuddy *buddy) {
	
}

static void buddy_status_changed_cb(GaimBuddy *buddy, GaimStatus *old, GaimStatus *new) {

}

static gboolean plugin_load(GaimPlugin *plugin) {
	void *blist_handle = gaim_blist_get_handle(); /* unused by gaim systray */
	void *conn_handle = gaim_connections_get_handle();
	void *conv_handle = gaim_conversations_get_handle();
	void *accounts_handle = gaim_accounts_get_handle();
	
	gaim_signal_connect(conn_handle, "signed-on", plugin,
			GAIM_CALLBACK(awn_signon_cb), NULL);
	gaim_signal_connect(conn_handle, "signed-off", plugin,
			GAIM_CALLBACK(awn_signoff_cb), NULL);
	gaim_signal_connect(accounts_handle, "account-status-changed", plugin,
			GAIM_CALLBACK(awn_update_status_cb), NULL);
	gaim_signal_connect(accounts_handle, "account-connecting", plugin,
			GAIM_CALLBACK(awn_update_status_cb), NULL);
	gaim_signal_connect(conv_handle, "received-im-msg", plugin,
			GAIM_CALLBACK(awn_update_status_cb), NULL);
	gaim_signal_connect(conv_handle, "conversation-created", plugin,
			GAIM_CALLBACK(awn_update_status_cb), NULL);
	gaim_signal_connect(conv_handle, "deleting-conversation", plugin,
			GAIM_CALLBACK(awn_update_status_cb), NULL);
	gaim_signal_connect(conv_handle, "conversation-updated", plugin,
			GAIM_CALLBACK(awn_conv_updated_cb), NULL);
	gaim_signal_connect(blist_handle, "buddy-signed-on", plugin,
			GAIM_CALLBACK(buddy_signon_cb), NULL);
	gaim_signal_connect(blist_handle, "buddy-signed-off", plugin,
			GAIM_CALLBACK(buddy_signoff_cb), NULL);
	gaim_signal_connect(blist_handle, "buddy-status-changed", plugin,
			GAIM_CALLBACK(buddy_status_changed_cb), NULL);
	
	awn_update_status();
	update_icon(status);
	return TRUE;
}

static gboolean plugin_unload(GaimPlugin *plugin) {
	unsetAwnIcon();
	return TRUE;
}	

static void init_plugin(GaimPlugin *plugin) {
}

GAIM_INIT_PLUGIN(hello_world, init_plugin, info);
